package com.tsfyun.scm.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.tsfyun.common.base.config.OrikaBeanMapper;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.extension.OrderItem;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.common.base.util.DateUtils;
import com.tsfyun.common.base.util.LocalDateTimeUtils;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.common.base.util.TsfPreconditions;
import com.tsfyun.common.base.vo.CurrencyVO;
import com.tsfyun.scm.system.dto.CustomsRateDTO;
import com.tsfyun.scm.system.entity.BankChinaRate;
import com.tsfyun.scm.system.entity.Currency;
import com.tsfyun.scm.system.entity.CustomsRate;
import com.tsfyun.scm.system.mapper.CustomsRateMapper;
import com.tsfyun.scm.system.service.IBankChinaRateService;
import com.tsfyun.scm.system.service.ICurrencyService;
import com.tsfyun.scm.system.service.ICustomsRateService;
import com.tsfyun.scm.system.util.RateUtil;
import com.tsfyun.scm.system.util.TsfWeekendSqls;
import com.tsfyun.scm.system.vo.CustomsRateVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;

import javax.xml.crypto.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 海关汇率服务实现类
 */
@Slf4j
@Service
public class CustomsRateServiceImpl extends ServiceImpl<CustomsRate> implements ICustomsRateService {

    @Autowired
    private OrikaBeanMapper beanMapper;

    @Autowired
    private CustomsRateMapper customsRateMapper;

    @Autowired
    private IBankChinaRateService bankChinaRateService;

    @Autowired
    private ICurrencyService currencyService;


    @Override
    public PageInfo<CustomsRate> page(CustomsRateDTO dto) {
        TsfWeekendSqls sqls = TsfWeekendSqls.<CustomsRate>custom()
                .andEqualTo(true,CustomsRate::getCurrencyId,dto.getCurrencyId())
                .andEqualTo(true,CustomsRate::getRateDate,dto.getRateDate());
        PageInfo<CustomsRate> pageInfo = super.pageList(dto.getPage(),dto.getLimit(),sqls, Lists.newArrayList(OrderItem.desc("publishDate"),OrderItem.desc("currencyId")));
        return pageInfo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(CustomsRateDTO dto) {
        /*
        Currency currency = currencyService.getById(dto.getCurrencyId());
        TsfPreconditions.checkArgument(Objects.nonNull(currency),new ServiceException("币制信息不存在"));
         */
        //判断当前币制是否存在海关汇率
        CustomsRate customsRate =  new CustomsRate();
        customsRate.setRate(dto.getRate());
        customsRate.setCurrencyId(dto.getCurrencyId());
        //customsRate.setCurrencyName(currency.getName());
        customsRate.setRateDate(dto.getRateDate());
        customsRate.setPublishDate(LocalDateTimeUtils.convertDateToLDT(dto.getPublishDate()));
        customsRate.setId(dto.getCurrencyId().concat(LocalDateTimeUtils.formatTime(LocalDateTimeUtils.convertDateToLDT(dto.getRateDate()),"yyyyMM")));
        try {
            super.saveNonNull(customsRate);
        } catch (DuplicateKeyException e) {
            throw new ServiceException(String.format("已经存在币制：%s，日期：%s的海关汇率",dto.getCurrencyId(), DateUtils.format(dto.getRateDate(),"yyyyMM")));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(CustomsRateDTO dto) {
        CustomsRate customsRate = super.getById(dto.getPreId());
        TsfPreconditions.checkArgument(Objects.nonNull(customsRate),new ServiceException("数据不存在"));
        /*
        Currency currency = currencyService.getById(dto.getCurrencyId());
        TsfPreconditions.checkArgument(Objects.nonNull(currency),new ServiceException("币制信息不存在"));
        dto.setCurrencyName(currency.getName());
         */
        //此处需要注意id的变化
        dto.setId(dto.getCurrencyId().concat(LocalDateTimeUtils.formatTime(LocalDateTimeUtils.convertDateToLDT(dto.getRateDate()),"yyyyMM")));
        try {
            customsRateMapper.update(dto);
        } catch (DuplicateKeyException e) {
            throw new ServiceException(String.format("已经存在币制：%s，日期：%s的海关汇率",dto.getCurrencyId(), DateUtils.format(dto.getRateDate(),"yyyyMM")));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(String id) {
        CustomsRate customsRate = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(customsRate),new ServiceException("数据不存在"));
        super.removeById(id);
    }

    @Override
    public CustomsRateVO detail(String id) {
        CustomsRate customsRate = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(customsRate),new ServiceException("数据不存在"));
        return beanMapper.map(customsRate,CustomsRateVO.class);
    }

    @Override
    public BigDecimal obtain(String currencyId, Date date) {
        if("CNY".equals(currencyId)){
            return BigDecimal.ONE;
        }
        CustomsRate query = new CustomsRate();
        query.setCurrencyId(currencyId);
        query.setRateDate(DateUtils.parseShort(DateUtils.format(date,"yyyy-MM-01")));
        CustomsRate customsRate = customsRateMapper.selectOne(query);
        if(Objects.nonNull(customsRate)){
            return customsRate.getRate();
        }
        return null;
    }

    @Override
    public BigDecimal obtain(String currencyId) {
        return obtain(currencyId,new Date());
    }

    @Override
    public void grabRate(Date date, Currency currency) {
        String month = DateUtils.format(date,"yyyyMM");
        String id = currency.getId().concat(month).intern();
        synchronized (id){
            CustomsRate customsRate = super.getById(id);
            if(Objects.nonNull(customsRate)) {
                log.info("{}海关汇率已经存在",id);
                return;
            }
            Date grabDate = RateUtil.calculationRateDate(date);
            String grabDateStr = DateUtils.formatShort(grabDate);
            log.info("开始查询：{} 中行汇率",grabDateStr);
            BankChinaRate bankChinaRate = bankChinaRateService.findLastOne(currency.getId(),grabDateStr);
            if(bankChinaRate == null){
                log.info("开始同步：{} 中行汇率",grabDateStr);
                //开始调用
                bankChinaRateService.grabRate(grabDateStr,currency);
                //再次获取
                bankChinaRate = bankChinaRateService.findLastOne(currency.getId(),grabDateStr);
            }
            if(bankChinaRate != null) {
                customsRate = new CustomsRate();
                customsRate.setId(id);
                customsRate.setCurrencyId(currency.getId());
                customsRate.setCurrencyName(currency.getName());
                customsRate.setPublishDate(bankChinaRate.getPublishDate());
                customsRate.setRateDate(DateUtils.parseShort(DateUtils.format(date,"yyyy-MM-01")));
                customsRate.setDateCreated(LocalDateTime.now());
                customsRate.setRate(bankChinaRate.getBocConversion().divide(BigDecimal.valueOf(100),6, BigDecimal.ROUND_HALF_UP));
                super.saveNonNull(customsRate);
            }

        }
    }

    @Override
    public List<CustomsRate> getNowAllCurrencyRate() {
        CustomsRate query = new CustomsRate();
        query.setRateDate(DateUtils.parseShort(DateUtils.format(new Date(),"yyyy-MM-01")));
        return customsRateMapper.select(query);
    }

    @Override
    public List<CustomsRateVO> clientCustomsRate(String queryMonth) {
        Date rateDate;
        if(StringUtils.isEmpty(queryMonth)) {
            rateDate = DateUtils.parseShort(DateUtils.format(new Date(),"yyyy-MM-01"));
        } else {
            rateDate = DateUtils.parseShort(queryMonth.concat("-01"));
        }
        List<CustomsRateVO> rateList = Lists.newArrayList();
        //获取所有启用的币制
        List<CurrencyVO> currencyVOList = currencyService.select();
        CustomsRate query = new CustomsRate();
        query.setRateDate(rateDate);
        List<CustomsRate> rates = customsRateMapper.select(query);
        if(CollUtil.isNotEmpty(rates)) {
            //按币制分组
            Map<String,CustomsRate> rateMap = rates.stream().collect(Collectors.toMap(CustomsRate::getCurrencyId, Function.identity()));
            currencyVOList.stream().forEach(cur -> {
                if(!"CNY".equals(cur.getId())) {
                    CustomsRate rate = rateMap.get(cur.getId());
                    if(Objects.isNull(rate)) {
                        rate = new CustomsRate();
                        rate.setCurrencyId(cur.getId());
                        rate.setCurrencyName(cur.getName());
                        rate.setRate(null);
                    }
                    CustomsRateVO customsRateVO = beanMapper.map(rate,CustomsRateVO.class);
                    rateList.add(customsRateVO);
                }
            });
        }else{
            currencyVOList.stream().forEach(cur -> {
                if(!"CNY".equals(cur.getId())){
                    CustomsRate rate = new CustomsRate();
                    rate.setCurrencyId(cur.getId());
                    rate.setCurrencyName(cur.getName());
                    rate.setRate(null);
                    CustomsRateVO customsRateVO = beanMapper.map(rate,CustomsRateVO.class);
                    rateList.add(customsRateVO);
                }
            });
            return rateList;
        }
        return rateList;
    }

    @Override
    public void grab() {
        log.info("扫描海关汇率数据开始......");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        List<Currency> currencyList = currencyService.list();
        if(CollUtil.isEmpty(currencyList)){return;}
        for(Currency currency : currencyList){
            if(!Objects.equals("CNY",currency.getId())){
                grabRate(new Date(),currency);
            }
        }
        stopWatch.stop();
        log.info("扫描海关汇率数据结束......，本次抓取耗时:{}s",stopWatch.getTotalTimeSeconds());
    }
}
